package com.example.socketchat.handler;

import com.example.socketchat.model.ChatMessage;
import com.example.socketchat.service.ChatMessageService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Socket服务器消息处理器
 * 
 * 处理所有客户端连接、断开和消息交换的核心组件
 * 负责管理连接的客户端、转发消息、维护在线状态
 */
@Slf4j
@Component
@Sharable
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {

    // 存储所有已连接的客户端Channel
    private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
    // 存储用户ID到Channel的映射
    private static final Map<String, Channel> USER_CHANNEL_MAP = new ConcurrentHashMap<>();
    
    // 用于在Channel中存储用户ID的AttributeKey
    private static final AttributeKey<String> USER_ID_KEY = AttributeKey.valueOf("userId");
    
    @Autowired
    private ChatMessageService chatMessageService;
    
    // JSON对象映射器
    private final ObjectMapper objectMapper;
    
    public ChatServerHandler() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.registerModule(new JavaTimeModule());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        // 当新的连接建立时，将channel添加到组中
        CHANNEL_GROUP.add(ctx.channel());
        log.info("客户端连接: {}", ctx.channel().remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        // 当连接断开时，将channel从组中移除
        CHANNEL_GROUP.remove(ctx.channel());
        
        // 获取用户ID
        String userId = ctx.channel().attr(USER_ID_KEY).get();
        if (userId != null) {
            // 从映射中移除
            USER_CHANNEL_MAP.remove(userId);
            
            // 发送断开连接的消息
            ChatMessage disconnectMessage = ChatMessage.createDisconnectMessage(userId);
            try {
                broadcastMessage(objectMapper.writeValueAsString(disconnectMessage));
                chatMessageService.saveMessage(disconnectMessage);
            } catch (Exception e) {
                log.error("发送断开连接消息失败", e);
            }
            
            log.info("用户 {} 断开连接", userId);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msgStr) {
        try {
            // 将JSON字符串转换为ChatMessage对象
            ChatMessage msg = objectMapper.readValue(msgStr, ChatMessage.class);
            
            String senderId = msg.getSenderId();
            
            // 如果是第一次连接消息，需要记录用户ID和Channel的映射关系
            if (msg.getType() == ChatMessage.MessageType.CONNECT) {
                ctx.channel().attr(USER_ID_KEY).set(senderId);
                USER_CHANNEL_MAP.put(senderId, ctx.channel());
                log.info("用户 {} 已连接", senderId);
            }
            
            // 保存消息到Redis
            chatMessageService.saveMessage(msg);
            
            // 根据消息类型处理
            switch (msg.getType()) {
                case CHAT:
                    // 点对点消息，发送给特定用户
                    String receiverId = msg.getReceiverId();
                    if (receiverId != null) {
                        Channel receiverChannel = USER_CHANNEL_MAP.get(receiverId);
                        if (receiverChannel != null && receiverChannel.isActive()) {
                            receiverChannel.writeAndFlush(msgStr);
                            log.debug("发送消息从 {} 到 {}: {}", senderId, receiverId, msg.getContent());
                        } else {
                            log.debug("接收者 {} 不在线或通道不活跃", receiverId);
                        }
                    }
                    break;
                    
                case BROADCAST:
                case CONNECT:
                case DISCONNECT:
                    // 广播消息，发送给所有连接的客户端
                    broadcastMessage(msgStr);
                    break;
            }
        } catch (Exception e) {
            log.error("处理消息时出错", e);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                // 读空闲，可能客户端已断开连接
                log.warn("读空闲超时，关闭连接: {}", ctx.channel().remoteAddress());
                ctx.close();
            } else if (event.state() == IdleState.WRITER_IDLE) {
                // 写空闲，发送心跳消息
                try {
                    ChatMessage heartbeat = ChatMessage.createBroadcastMessage("server", "heartbeat");
                    ctx.writeAndFlush(objectMapper.writeValueAsString(heartbeat));
                } catch (Exception e) {
                    log.error("发送心跳消息失败", e);
                }
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("处理过程中发生异常", cause);
        ctx.close();
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 将接收到的消息委托给父类处理，最终会调用channelRead0方法
        super.channelRead(ctx, msg);
        log.debug("收到消息: {}", msg);
    }
    
    /**
     * 广播消息给所有连接的客户端
     */
    private void broadcastMessage(String message) {
        CHANNEL_GROUP.writeAndFlush(message);
        log.debug("广播消息: {}", message);
    }
} 